#ifndef _TJU_TCP_H_
#define _TJU_TCP_H_

#include "global.h"
#include "tju_packet.h"
#include "kernel.h"

/*
创建 TCP socket
初始化对应的结构体
设置初始状态为 CLOSED
*/
tju_tcp_t *tju_socket();

/*
绑定监听的地址 包括ip和端口
*/
int tju_bind(tju_tcp_t *sock, tju_sock_addr bind_addr);

/*
被动打开 监听bind的地址和端口
设置socket的状态为LISTEN
*/
int tju_listen(tju_tcp_t *sock);

/*
接受连接
返回与客户端通信用的socket
这里返回的socket一定是已经完成3次握手建立了连接的socket
因为只要该函数返回, 用户就可以马上使用该socket进行send和recv
*/
tju_tcp_t *tju_accept(tju_tcp_t *sock);

/*
连接到服务端
该函数以一个socket为参数
调用函数前, 该socket还未建立连接
函数正常返回后, 该socket一定是已经完成了3次握手, 建立了连接
因为只要该函数返回, 用户就可以马上使用该socket进行send和recv
*/
int tju_connect(tju_tcp_t *sock, tju_sock_addr target_addr);

int tju_send(tju_tcp_t *sock, const void *buffer, int len);
int tju_recv(tju_tcp_t *sock, void *buffer, int len);

/*
关闭一个TCP连接
这里涉及到四次挥手
*/
int tju_close(tju_tcp_t *sock);

#define min(x, y) ((x < y) ? (x) : (y)) // 宏定义 min() 函数
#define max(x,y) ((x>y)?(x):(y)) //宏定义max()函数

int tju_handle_packet(tju_tcp_t *sock, char *pkt);

void *tju_close_thread(void *arg);//关闭连接的线程函数

uint16_t generate_port();//随机分配端口号

void *sending_thread(void *arg);//用于发送的线程

void *retrans_thread(void *arg);//用于重传的线程

void timeout_handler(int signo);//超时处理函数

void startTimer(tju_tcp_t *sock);//计时器开始计时

void stopTimer(void);//计时器结束计时

uint16_t get_wnd_move_len(uint8_t *mark);//用于获得窗口前移长度的函数

int Caltimeout(tju_tcp_t *sock);

/*
记录日志
*/
struct timeval start;

FILE *server_event_log;
FILE *client_event_log;

void init_log();        // 初始化
void close_log();       // 关闭
long getCurrentTime();      // 返回调用时间
FILE* getEventlog();

#define _SEND_LOG_(pkt) \
{\
    fprintf(getEventlog(),"[%ld] [SEND] [seq:%d ack:%d flag:%d length:%d]\n",\
    getCurrentTime(),get_seq(pkt),get_ack(pkt),get_flags(pkt),get_plen(pkt)-get_hlen(pkt));\
}

#define _RECV_LOG_(pkt) \
{\
    fprintf(getEventlog(),"[%ld] [RECV] [seq:%d ack:%d flag:%d length:%d]\n",\
    getCurrentTime(),get_seq(pkt),get_ack(pkt),get_flags(pkt),get_plen(pkt)-get_hlen(pkt));\
}

#define _CWND_LOG_(sock,type) \
{\
    fprintf(getEventlog(),"[%ld] [CWND] [type:%d size:%d]\n",\
    getCurrentTime(),type,sock->window.wnd_send->cwnd);\
}

#define _RWND_LOG_(sock) \
{\
    fprintf(getEventlog(),"[%ld] [RWND] [size:%d]\n",\
    getCurrentTime(),sock->window.wnd_send->rwnd);\
}

#define _SWND_LOG_(sock) \
{\
    fprintf(getEventlog(),"[%ld] [SWND] [size:%d]\n",\
    getCurrentTime(),sock->window.wnd_send->window_size);\
}

#define _RTTS_LOG_(sock, sample_RTT) \
{\
    uint32_t estimated = sock->window.wnd_send->SRTT;\
    uint32_t dev = sock->window.wnd_send->dev_rtt;\
    uint32_t timeoutinterval = sock->window.wnd_send->timeout.it_value.tv_usec;\
    fprintf(getEventlog(),"[%ld] [RTTS] [SampleRTT:%ld EstimatedRTT:%d DeviationRTT:%d TimeoutInterval:%d]\n",\
    getCurrentTime(),sample_RTT,estimated,dev,timeoutinterval);\
}

// 还有一个吞吐量的
#define _DELV_LOG_(seq,len) \
{\
    fprintf(getEventlog(),"[%ld] [DELV] [seq:%d size:%d]\n",\
    getCurrentTime(),seq,len);\
}
#endif
